﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.Windows.Threading;
using TSL.Model;
using System.Xml;
using FolderPickerLib;
using System.IO;
using System.Xml.Serialization;

namespace TSL
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        const float MaxDepthDistance = 4095; // max value returned
        const float MinDepthDistance = 850; // min value returned
        const float MaxDepthDistanceOffset = MaxDepthDistance - MinDepthDistance;

        const int skeletonCount = 6;
        Skeleton[] allSkeletons = new Skeleton[skeletonCount];

        bool isRecord = false; bool isMoving = false;
        private DispatcherTimer timer1;
        private int counter = 60;
        private int frameCounter = 0;

        private JoinFrame headJointFrame, leftJointFrame, rightJointFrame, shoulderLeftJointFrame, shoulderRightJointFrame, hipLeftJointFrame, hipRightJointFrame;
        private TSL.Model.Frame jointFrame;
        private List<TSL.Model.Frame> totalFrame;
        private Gesture gesture;

        KinectModule kin;

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            kinectSensorChooser1.KinectSensorChanged += new DependencyPropertyChangedEventHandler(kinectSensorChooser1_KinectSensorChanged);
            timer1 = new DispatcherTimer();
            timer1.Interval = new TimeSpan(0, 0, 1);
            timer1.Tick += new EventHandler(timer1_Tick);
            frameCounter = 0;
            totalFrame = new List<TSL.Model.Frame>();
        }

        void kinectSensorChooser1_KinectSensorChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            KinectSensor oldSensor = (KinectSensor)e.OldValue;
            //stop the old sensor
            if (oldSensor != null)
            {
                oldSensor.Stop();
                //oldSensor.AudioSource.Stop();
            }

            KinectSensor newSensor = (KinectSensor)e.NewValue;
            kin = new KinectModule(newSensor);

            if (newSensor != null)
            {
                //kin = new KinectModule(kinectSensorChooser1.Kinect);
                //logBlock.Text = kin.getHeadData();
                newSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                newSensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
                newSensor.SkeletonStream.Enable();
                newSensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(newSensor_AllFramesReady);
                try
                {
                    newSensor.Start();
                }
                catch (System.IO.IOException)
                {
                    kinectSensorChooser1.AppConflictOccurred();
                } 
            }
        }

        void newSensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            if (kin.CheckReadyStance())
            {
                logText.Text = "In ready Stance";
            }
            else
            {
                logText.Text = "Not in Ready Stance";
            }
            if (isRecord)
            {
                //add countdown time condition to stop rec after x sec
                //add get joint data save to array
                //show frame counter on logTxt
                if (kin.CheckReadyStance())
                {
                    headJointFrame = new JoinFrame();
                    headJointFrame.X = kin.getHeadPos("x"); headJointFrame.Y = kin.getHeadPos("y"); headJointFrame.Z = kin.getHeadPos("z");

                    leftJointFrame = new JoinFrame();
                    leftJointFrame.X = kin.getLeftHandPos("x"); leftJointFrame.Y = kin.getLeftHandPos("y"); leftJointFrame.Z = kin.getLeftHandPos("z");

                    rightJointFrame = new JoinFrame();
                    rightJointFrame.X = kin.getRightHandPos("x"); rightJointFrame.Y = kin.getRightHandPos("y"); rightJointFrame.Z = kin.getRightHandPos("z");

                    shoulderLeftJointFrame = new JoinFrame();
                    shoulderLeftJointFrame.X = kin.getLeftShoulderPos("x"); shoulderLeftJointFrame.Y = kin.getLeftShoulderPos("y"); shoulderLeftJointFrame.Z = kin.getLeftShoulderPos("z");

                    shoulderRightJointFrame = new JoinFrame();
                    shoulderRightJointFrame.X = kin.getRightShoulderPos("x"); shoulderRightJointFrame.Y = kin.getRightShoulderPos("y"); shoulderRightJointFrame.Z = kin.getRightShoulderPos("z");

                    hipLeftJointFrame = new JoinFrame();
                    hipLeftJointFrame.X = kin.getLeftHipPos("x"); hipLeftJointFrame.Y = kin.getLeftHipPos("y"); hipLeftJointFrame.Z = kin.getLeftHipPos("z");

                    hipRightJointFrame = new JoinFrame();
                    hipRightJointFrame.X = kin.getRightHipPos("x"); hipRightJointFrame.Y = kin.getRightHipPos("y"); hipRightJointFrame.Z = kin.getRightHipPos("z");

                    jointFrame = new TSL.Model.Frame();
                    jointFrame.FrameNo = frameCounter;
                    jointFrame.Head = headJointFrame;
                    jointFrame.HandLeft = leftJointFrame; jointFrame.HandRight = rightJointFrame;
                    jointFrame.ShoulderLeft = shoulderLeftJointFrame; jointFrame.ShoulderRight = shoulderRightJointFrame;
                    jointFrame.HipLeft = hipLeftJointFrame; jointFrame.HipRight = hipRightJointFrame;
                    logBlock.Text = frameCounter.ToString();
                    totalFrame.Add(jointFrame);
                    frameCounter += 1;
                }
            }
        }

        void StopKinect(KinectSensor sensor)
        {
            if (sensor != null)
            {
                sensor.Stop();
                //sensor.AudioSource.Stop();
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            StopKinect(kinectSensorChooser1.Kinect);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            var adjustWindow = new AdjustAngle(kinectSensorChooser1.Kinect);
            adjustWindow.Show();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            frameCounter = 0;
            if (!(gestureNameBlock.Text.Equals("") && gestureNoBlock.Text.Equals("") && gestureByBlock.Text.Equals("")))
            {
                counter = 4;
                overlayText.Text = "Prepare to input in " + counter + " sec.";
                timer1.Start();
                //isRecord = true;
            }
            else
            {
                string messageBoxText = "Please input all field before start record.";
                string caption = "Gesture Recorder";
                MessageBoxButton button = MessageBoxButton.OK;
                MessageBoxImage icon = MessageBoxImage.Warning;
                MessageBoxResult result = System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            counter--;
            if (!isRecord)
            {
                if (counter == 0)
                {
                    overlayText.Text = " ";
                    timer1.Stop();
                    if (kin.CheckSkeleton())
                    {
                        counter = 3;
                        overlayText.Text = "Record will stop in " + counter + " sec.";
                        isRecord = true;
                        timer1.Start();
                    }
                    else
                    {
                        string messageBoxText = "Please stand in front of kinect sensor before start record.";
                        string caption = "Gesture Recorder";
                        MessageBoxButton button = MessageBoxButton.OK;
                        MessageBoxImage icon = MessageBoxImage.Warning;
                        MessageBoxResult result = System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);
                    }
                    
                }
                else
                {
                    overlayText.Text = "Prepare to input in " + counter + " sec.";
                }
            }
            else if (isRecord)
            {
                if (counter == 0)
                {
                    overlayText.Text = "Stop Record";
                    isRecord = false;
                    timer1.Stop();
                    overlayText.Text = "Record : " + frameCounter + " frames.";
                    logBlock.Text = totalFrame.Count.ToString();
                    string messageBoxText = "Do you want to save your Gesture?";
                    string caption = "Gesture Recorder";
                    MessageBoxButton button = MessageBoxButton.YesNo;
                    MessageBoxImage icon = MessageBoxImage.Warning;
                    MessageBoxResult result = System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);

                    switch (result)
                    {
                        case MessageBoxResult.Yes:
                            if (frameCounter != 0)
                            {
                                gesture = new Gesture();
                                string binary = Convert.ToString(int.Parse(gestureNoBlock.Text)*2, 2); 
                                gesture.GestureNo = binary.PadLeft(10, '0');
                                gesture.GestureName = gestureNameBlock.Text;
                                gesture.GestureBy = gestureByBlock.Text;
                                gesture.GestureFrames = totalFrame;
                                gesture.TotalFrame = totalFrame.Count;
                                if (Directory.Exists(pathText.Text))
                                {
                                    String fileName = gestureNoBlock.Text + "_" + gestureNameBlock.Text + "_by_" + gestureByBlock.Text;
                                    XMLModule xmlMod = new XMLModule();
                                    xmlMod.SerializeGesture(pathText.Text, fileName, gesture);
                                    frameCounter = 0;
                                    totalFrame.Clear();
                                }
                                else
                                {
                                    messageBoxText = "Your save folder path is no exists please select a new path.";
                                    caption = "Gesture Recorder";
                                    button = MessageBoxButton.OK;
                                    icon = MessageBoxImage.Warning;
                                    MessageBoxResult result2 = System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);
                                    switch (result2)
                                    {
                                        case MessageBoxResult.OK:
                                            var dlg = new FolderPickerDialog();
                                            if (dlg.ShowDialog() == true)
                                            {
                                                string path = dlg.SelectedPath;
                                                path = path.Replace(@"\", @"\\");
                                                pathText.Text = path;

                                                String fileName = gestureNoBlock.Text +"_"+ gestureNameBlock.Text + "_by_" + gestureByBlock.Text;
                                                XMLModule xmlMod = new XMLModule();
                                                xmlMod.SerializeGesture(pathText.Text, fileName, gesture);
                                                frameCounter = 0;
                                                totalFrame.Clear();
                                            }
                                            break;
                                        case MessageBoxResult.Cancel:
                                            break;
                                    }
                                }
                                totalFrame.Clear();
                            }
                            else
                            {
                                messageBoxText = "Cannot record gesture. Please try again.";
                                caption = "Gesture Recorder";
                                button = MessageBoxButton.OK;
                                icon = MessageBoxImage.Error;
                                MessageBoxResult result3 = System.Windows.MessageBox.Show(messageBoxText, caption, button, icon);
                                switch (result3)
                                {
                                    case MessageBoxResult.OK:
                                        frameCounter = 0;
                                        break;
                                    default:
                                        break;
                                }
                            }
                            break;
                        case MessageBoxResult.No:
                            frameCounter = 0;
                            break;
                    }
                }
                else
                {
                    overlayText.Text = "Record will stop in " + counter + " sec.";
                }
            }
            

        }

        private void folderButton_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new FolderPickerDialog();
            if (dlg.ShowDialog() == true)
            {
                string path = dlg.SelectedPath;
                path = path.Replace(@"\", @"\\");
                pathText.Text = path+@"\\";
            }
        }

        private void trainButton_Click(object sender, RoutedEventArgs e)
        {
            var mainmenu = new MainMenu();
            mainmenu.Show();
            this.Close();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            StopKinect(kinectSensorChooser1.Kinect);
        }
    }
}
